<?php

/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */

/**
 * This file contains the PDODB_Manager class.
 *
 * PHP version 5
 *
 * This file is part of PEAR::PDODB - A database abstraction layer for PHP5 built
 * using PDO. PHP version 5.1+ is recommended.
 *
 * PEAR::PDODB is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * PEAR::PDODB is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with PEAR::PDODB. If not, see <http://www.gnu.org/licenses/>.
 *
 * @package     PDODB
 * @category    Database
 * @author      Lukas Smith <smith@pooteeweet.org>
 * @author      Michael J. I. Jackson <mjijackson@gmail.com>
 * @copyright   1998-2007 Manuel Lemos, Tomas V.V. Cox, Stig S. Bakken, Lukas Smith
 * @copyright   2007 Michael J. I. Jackson
 * @license     http://www.gnu.org/licenses/lgpl-3.0.txt GNU LGPL 3.0
 * @version     SVN: $Id: Manager.php 2 2007-11-27 17:20:29Z mjijackson $
 * @link        http://pear.php.net/packages/PDODB
 */

/**
 * The base class for all PDODB database manager classes.
 *
 * @package     PDODB
 * @category    Database
 * @author      Lukas Smith <smith@pooteeweet.org>
 * @author      Michael J. I. Jackson <mjijackson@gmail.com>
 */
abstract class PDODB_Manager extends PDODB_Module
{

    /**
     * Creates a database with the given name.
     *
     * @param   string  $name       The name for the new database
     * @return  bool                True on success, false otherwise
     * @throws  PDODB_UnsupportedFeatureException   If the connection doesn't support
     *                                              the use of this function
     * @access  public
     */
    public function createDatabase($name)
    {
        $db = $this->getConnection();
        throw new PDODB_UnsupportedFeatureException(__FUNCTION__, $db->driver());
    }

    /**
     * Drops the specified database.
     *
     * @param   string  $name       The name of the database to drop
     * @return  bool                True on success, false otherwise
     * @throws  PDODB_UnsupportedFeatureException   If the connection doesn't support
     *                                              the use of this function
     * @access  public
     */
    public function dropDatabase($name)
    {
        $db = $this->getConnection();
        throw new PDODB_UnsupportedFeatureException(__FUNCTION__, $db->driver());
    }

    /**
     * Creates the specified table in the database. The $fields parameter is an
     * associative array, the indices of which declare the names of the fields.
     * Each value of the array is the corresponding field's definition. A field
     * definition is an associative array that specifies the options for the
     * field. Available options for field definitions include:
     *
     * <ul>
     * <li>type - (string) The field's data type</li>
     * <li>length - (int) The field's length. If this value is missing, and the
     * field is a text field, the default_text_field_length connection option will
     * be used.</li>
     * <li>default - (mixed) The field's DEFAULT value</li>
     * <li>notnull - (bool) True to prevent the field from being NULL</li>
     * <li>unsigned - (bool) True to make the field UNSIGNED</li>
     * <li>fixed - (bool) True to create a text field of fixed length</li>
     * <li>scale - (int) The number of decimal places to use in a DECIMAL type
     * field. If this value is missing, the default_decimal_places connection
     * option will be used.</li>
     * <li>charset - (string) The CHARACTER SET to use for the field</li>
     * <li>collation - (string) The default COLLATION to use for this field</li>
     * <li>autoincrement - (bool) True to create an auto-incrementing field</li>
     * </ul>
     *
     * Please note that all field definition options may not be available on a
     * particular DBMS. Those options that are not supported on the DBMS will
     * simply be ignored. Also, some options may be ignored depending on the
     * type of the field. For example, specifying an 'unsigned' option on a text
     * field just won't work. An example $fields array:
     *
     * <code>
     * $fields = array(
     *     'id' => array(
     *         'type' => 'integer',
     *         'unsigned' => 1,
     *         'notnull' => 1,
     *         'autoincrement' => 1
     *     ),
     *     'name' => array(
     *         'type' => 'text',
     *         'length' => 12
     *     ),
     *     'balance' => array(
     *         'type' => 'decimal',
     *         'scale' => 2,
     *         'default' => 0
     *     )
     * )
     * </code>
     *
     * The $options parameter is used to specify options for the table. It is
     * an associative array consisting of option names => values. Available
     * table options include:
     *
     * <ul>
     * <li>comment - (string) A comment to use for the table</li>
     * <li>primary - (array) The names of the fields to use as primary keys</li>
     * <li>temporary - (bool) True to create a temporary table</li>
     * <li>charset - (string) The CHARACTER SET setting for the table</li>
     * <li>collate - (string) The COLLATION setting for the table</li>
     * <li>type - (string) The type of table to create</li>
     * </ul>
     *
     * Please note that all table options may not be available on a particular
     * DBMS. Those options that are not supported on the DBMS will simply be
     * ignored. For example, setting the 'comment' option on a DBMS that doesn't
     * support table comments just won't work. An example $options array:
     *
     * <code>
     * $options = array(
     *     'comment' => 'A table comment',
     *     'primary' => array('id'),
     *     'charset' => 'utf8',
     *     'collate' => 'utf8_unicode_ci',
     *     'type'    => 'innodb',
     * )
     * </code>
     *
     * @param   string  $name       The name of the table to create
     * @param   array   $fields     An array of field definitions
     * @param   array   $options    An array of table options
     * @return  bool                True on success, false otherwise
     * @access  public
     */
    public function createTable($name, $fields, $options = array())
    {
        $db = $this->getConnection();
        return $db->exec($this->getCreateTableQuery($name, $fields, $options));
    }

    /**
     * Creates a basic CREATE TABLE statement. See the {@link createTable()}
     * documentation for more information on this function's parameters.
     *
     * @param   string      $name       The database name
     * @param   array       $fields     An array of field definitions
     * @param   array       $options    An array of table options
     * @return  string                  The CREATE TABLE query
     * @access  public
     */
    public function getCreateTableQuery($name, $fields, $options = array())
    {
        $db = $this->getConnection();

        $query_fields = $this->getFieldDeclarationList($fields);
        if (!empty($options['primary'])) {
            $p_keys = array();
            foreach ($options['primary'] as $p_key) {
                $p_keys[] = $db->quoteIdentifier($p_key, true);
            }
            $query_fields .= ', PRIMARY KEY (' . implode(', ', $p_keys) . ')';
        }

        $query = 'CREATE ';
        if (!empty($options['temporary'])) {
            $query .= $this->getTemporaryTableQuery();
        }

        return $query . 'TABLE ' . $db->quoteIdentifier($name, true)
            . " ($query_fields)";
    }

    /**
     * Gets a keyword to insert between CREATE ... TABLE in order to create a
     * temporary table. By default, this method returns 'TEMPORARY '. This
     * may not work for all DBMS and should be overridden in child classes
     * accordingly.
     *
     * @return  string              The SQL keyword to use
     * @access  protected
     */
    protected function getTemporaryTableQuery()
    {
        return 'TEMPORARY ';
    }

    /**
     * Gets a list of field declarations that may be used in a CREATE TABLE
     * statement. See the {@link createTable()} documentation for information
     * on defining fields.
     *
     * @param   array   $fields     An array of field definitions
     * @return  string              A comma-separated list of field declarations
     * @access  public
     */
    public function getFieldDeclarationList($fields)
    {
        $db = $this->getConnection();

        foreach ($fields as $field_name => $field) {
            $query_fields[] = $db->datatype->getDeclaration($field['type'], $field_name, $field);
        }

        return implode(', ', $query_fields);
    }

    /**
     * Drops the specified table from the database.
     *
     * @param   string  $name       The name of the table to drop
     * @return  bool                True on success, false otherwise
     * @access  public
     */
    public function dropTable($name)
    {
        $db = $this->getConnection();
        return $db->exec('DROP TABLE ' . $db->quoteIdentifier($name, true));
    }

    /**
     * Creates a sequence in the database.
     *
     * @param   string  $name       The name of the sequence to be created
     * @param   int     $start      The start value of the sequence, defaults to 1
     * @return  bool                True on success, false on failure
     * @throws  PDODB_UnsupportedFeatureException       If the connection does not
     *                                                  support sequences
     * @throws  PDODB_ConnectionException               If the sequence creation
     *                                                  fails
     * @access  public
     */
    public function createSequence($name, $start = 1)
    {
        $db = $this->getConnection();
        throw new PDODB_UnsupportedFeatureException(__FUNCTION__, $db->driver());
    }

    /**
     * Drops an existing sequence from the database.
     *
     * @param   string  $name       The name of the sequence to be dropped
     * @return  bool                True on success, false on failure
     * @throws  PDODB_UnsupportedFeatureException       If the connection does not
     *                                                  support sequences
     * @throws  PDODB_ConnectionException               If the sequence drop
     *                                                  fails
     * @access  public
     */
    public function dropSequence($name)
    {
        $db = $this->getConnection();
        throw new PDODB_UnsupportedFeatureException(__FUNCTION__, $db->driver());
    }

}

?>
